/*
 * CalibratorGUI.java
 */

package itesm.gvision.apps.calibrator;

import itesm.gvision.components.ImagePanelScroller;
import itesm.gvision.image.process.HomographyImageProjection;
import itesm.gvision.image.process.HomographyTransform;
import itesm.gvision.image.tools.ImageTools;
import itesm.gvision.image.tools.JPEGFileManager;
import itesm.gvision.tools.FileChooserImage;
import itesm.gvision.tools.PointDouble;

import java.awt.Cursor;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileWriter;
import java.text.DecimalFormat;
import java.util.Vector;

import javax.swing.DefaultListModel;
import javax.swing.JFileChooser;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.UIManager;

//----------------------------------------------------------------------------------
/**
 * Camera calibration utility GUI. Front-end for the OCV calibration library.
 * @author  hugo
 */
public class JCamCalib extends javax.swing.JFrame 
{
	/** Image list */
	private Vector imagesCalib = new Vector();

	/** Image dimensions */
	private int fw, fh;
	
	/** OCV Bridge */
	private CalibratorOCV cocv = new CalibratorOCV();

	/** Distorted image */
	private BufferedImage distorted;
	
	/** Undistorted image */
	private BufferedImage undistorted;

	/** Homography matrices */
	private double homoI2W[], homoW2I[];
	
	/** Homography transform */
	private HomographyTransform homoTrans;
	
	/** Zoom factor for homography point selection */
	private int scaleHomoPoint = 20;
	
	/** Size for subimage area selection */
	private int subImageSize = 20;
	
	/** Homography image projection opertations */
	private HomographyImageProjection hip;

	//----------------------------------------------------------------------------------
	/** Creates new form CalibratorGUI */
	public JCamCalib() 
	{
		initComponents();
		//this.pnlIPCalibrationImage.add(this.cip);
		this.pnlIPCalibrationImages.add(this.cip);
		this.pnlIPUndistortedImage.add(this.cipUndistored);
		this.pnlHMImageReference.add(this.chomoip);
		this.pnlHMTestMode.add(this.chomoipTest);
		this.pnlHMImageProjection.add(this.ips);
	}
	
	//----------------------------------------------------------------------------------
	/** This method is called from within the constructor to
	 * initialize the form.
	 * WARNING: Do NOT modify this code. The content of this method is
	 * always regenerated by the Form Editor.
	 */
    private void initComponents() {//GEN-BEGIN:initComponents
        jTabbedPane1 = new javax.swing.JTabbedPane();
        jPanel1 = new javax.swing.JPanel();
        jSplitPane1 = new javax.swing.JSplitPane();
        jPanel5 = new javax.swing.JPanel();
        jPanel7 = new javax.swing.JPanel();
        jPanel10 = new javax.swing.JPanel();
        btnIPAddFromFile = new javax.swing.JButton();
        btnIPAddFromCamera = new javax.swing.JButton();
        jPanel11 = new javax.swing.JPanel();
        btnIPDel = new javax.swing.JButton();
        jPanel8 = new javax.swing.JPanel();
        jScrollPane1 = new javax.swing.JScrollPane();
        lstImagesCalib = lstImagesCalib = new JList(lstImgsCalib);
        jPanel9 = new javax.swing.JPanel();
        btnIPCompute = new javax.swing.JButton();
        jPanel6 = new javax.swing.JPanel();
        jtpIntCalOptions = new javax.swing.JTabbedPane();
        pnlIPCalibrationImages = new javax.swing.JPanel();
        pnlIPResults = new javax.swing.JPanel();
        jPanel12 = new javax.swing.JPanel();
        eIPMatrix0 = new javax.swing.JTextField();
        eIPMatrix1 = new javax.swing.JTextField();
        eIPMatrix2 = new javax.swing.JTextField();
        eIPMatrix3 = new javax.swing.JTextField();
        eIPMatrix4 = new javax.swing.JTextField();
        eIPMatrix5 = new javax.swing.JTextField();
        eIPMatrix6 = new javax.swing.JTextField();
        eIPMatrix7 = new javax.swing.JTextField();
        eIPMatrix8 = new javax.swing.JTextField();
        jPanel13 = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        eIPDistk1 = new javax.swing.JTextField();
        lblIPDistp1 = new javax.swing.JLabel();
        eIPDistp1 = new javax.swing.JTextField();
        lblIPDistk2 = new javax.swing.JLabel();
        eIPDistk2 = new javax.swing.JTextField();
        jLabel4 = new javax.swing.JLabel();
        eIPDistp2 = new javax.swing.JTextField();
        jPanel16 = new javax.swing.JPanel();
        jPanel17 = new javax.swing.JPanel();
        eIPConfigFmt = new javax.swing.JTextArea();
        btnIP = new javax.swing.JButton();
        jPanel14 = new javax.swing.JPanel();
        pnlIPUndistortedImage = new javax.swing.JPanel();
        jPanel15 = new javax.swing.JPanel();
        btnIPUndistortedLoad = new javax.swing.JButton();
        btnIPUndistortedSaveAs = new javax.swing.JButton();
        btnIPUndist = new javax.swing.JToggleButton();
        jPanel3 = new javax.swing.JPanel();
        jSplitPane2 = new javax.swing.JSplitPane();
        jPanel18 = new javax.swing.JPanel();
        jPanel20 = new javax.swing.JPanel();
        btnHMPointAddMode = new javax.swing.JToggleButton();
        btnHMPointEdit = new javax.swing.JButton();
        btnHMPointDel = new javax.swing.JButton();
        jPanel33 = new javax.swing.JPanel();
        jLabel2 = new javax.swing.JLabel();
        jPanel21 = new javax.swing.JPanel();
        jScrollPane2 = new javax.swing.JScrollPane();
        lstHMPoints = lstHMPoints = new JList(lstHomoPoints);
        jPanel24 = new javax.swing.JPanel();
        btnHMGetMatrix = new javax.swing.JButton();
        jPanel19 = new javax.swing.JPanel();
        jtpHMOptions = new javax.swing.JTabbedPane();
        jPanel25 = new javax.swing.JPanel();
        jPanel22 = new javax.swing.JPanel();
        btnHMLoadUndistorted = new javax.swing.JButton();
        pnlHMImageReference = new javax.swing.JPanel();
        jPanel23 = new javax.swing.JPanel();
        lblHMImgCoordinates = new javax.swing.JLabel();
        jPanel26 = new javax.swing.JPanel();
        jPanel28 = new javax.swing.JPanel();
        eHM0 = new javax.swing.JTextField();
        eHM1 = new javax.swing.JTextField();
        eHM2 = new javax.swing.JTextField();
        eHM3 = new javax.swing.JTextField();
        eHM4 = new javax.swing.JTextField();
        eHM5 = new javax.swing.JTextField();
        eHM6 = new javax.swing.JTextField();
        eHM7 = new javax.swing.JTextField();
        eHM8 = new javax.swing.JTextField();
        jPanel32 = new javax.swing.JPanel();
        eHM_w2i_0 = new javax.swing.JTextField();
        eHM_w2i_1 = new javax.swing.JTextField();
        eHM_w2i_2 = new javax.swing.JTextField();
        eHM_w2i_3 = new javax.swing.JTextField();
        eHM_w2i_4 = new javax.swing.JTextField();
        eHM_w2i_5 = new javax.swing.JTextField();
        eHM_w2i_6 = new javax.swing.JTextField();
        eHM_w2i_7 = new javax.swing.JTextField();
        eHM_w2i_8 = new javax.swing.JTextField();
        jPanel29 = new javax.swing.JPanel();
        jPanel31 = new javax.swing.JPanel();
        eHMConfigFmt = new javax.swing.JTextArea();
        btnHMSaveMatrix = new javax.swing.JButton();
        jPanel30 = new javax.swing.JPanel();
        jPanel27 = new javax.swing.JPanel();
        pnlHMTestMode = new javax.swing.JPanel();
        jPanel35 = new javax.swing.JPanel();
        lblHMTestImagePoint = new javax.swing.JLabel();
        lblHMTestWorldPoint = new javax.swing.JLabel();
        jPanel34 = new javax.swing.JPanel();
        pnlHMImageProjection = new javax.swing.JPanel();
        jPanel37 = new javax.swing.JPanel();
        jPanel36 = new javax.swing.JPanel();
        jLabel6 = new javax.swing.JLabel();
        cbxHMImgProjectionOrigin = new javax.swing.JComboBox();
        jLabel3 = new javax.swing.JLabel();
        eHMImageProjectionScale = new javax.swing.JTextField();
        jLabel5 = new javax.swing.JLabel();
        eHMImgProjectorX1 = new javax.swing.JTextField();
        eHMImgProjectorY1 = new javax.swing.JTextField();
        eHMImgProjectorX2 = new javax.swing.JTextField();
        eHMImgProjectorY2 = new javax.swing.JTextField();
        btnHMImageProjScaleGenerate = new javax.swing.JButton();
        jPanel38 = new javax.swing.JPanel();
        btnHMImageProjScaleApply1 = new javax.swing.JButton();
        jPanel4 = new javax.swing.JPanel();
        jPanel2 = new javax.swing.JPanel();
        jButton1 = new javax.swing.JButton();
        jButton2 = new javax.swing.JButton();

        getContentPane().setLayout(new javax.swing.BoxLayout(getContentPane(), javax.swing.BoxLayout.Y_AXIS));

        setTitle("JCamCalib :: A camera calibration utility");
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                exitForm(evt);
            }
        });

        jTabbedPane1.setPreferredSize(new java.awt.Dimension(229, 32767));
        jPanel1.setLayout(new java.awt.BorderLayout());

        jPanel5.setLayout(new javax.swing.BoxLayout(jPanel5, javax.swing.BoxLayout.Y_AXIS));

        jPanel10.setBorder(new javax.swing.border.TitledBorder("Add image from:"));
        btnIPAddFromFile.setText("File...");
        btnIPAddFromFile.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnIPAddFromFileActionPerformed(evt);
            }
        });

        jPanel10.add(btnIPAddFromFile);

        btnIPAddFromCamera.setText("Camera");
        btnIPAddFromCamera.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnIPAddFromCameraActionPerformed(evt);
            }
        });

        jPanel10.add(btnIPAddFromCamera);

        jPanel7.add(jPanel10);

        jPanel11.setBorder(new javax.swing.border.TitledBorder("Selection:"));
        btnIPDel.setText("Delete");
        btnIPDel.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnIPDelActionPerformed(evt);
            }
        });

        jPanel11.add(btnIPDel);

        jPanel7.add(jPanel11);

        jPanel5.add(jPanel7);

        jPanel8.setLayout(new java.awt.BorderLayout());

        lstImagesCalib.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
        lstImagesCalib.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
                lstImagesCalibValueChanged(evt);
            }
        });

        jScrollPane1.setViewportView(lstImagesCalib);

        jPanel8.add(jScrollPane1, java.awt.BorderLayout.CENTER);

        jPanel5.add(jPanel8);

        btnIPCompute.setForeground(new java.awt.Color(255, 0, 0));
        btnIPCompute.setText("Calibrate");
        btnIPCompute.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnIPComputeActionPerformed(evt);
            }
        });

        jPanel9.add(btnIPCompute);

        jPanel5.add(jPanel9);

        jSplitPane1.setLeftComponent(jPanel5);

        jPanel6.setLayout(new java.awt.BorderLayout());

        jtpIntCalOptions.setTabPlacement(javax.swing.JTabbedPane.BOTTOM);
        pnlIPCalibrationImages.setLayout(new java.awt.BorderLayout());

        jtpIntCalOptions.addTab("Calibration images", pnlIPCalibrationImages);

        pnlIPResults.setLayout(new javax.swing.BoxLayout(pnlIPResults, javax.swing.BoxLayout.Y_AXIS));

        jPanel12.setLayout(new java.awt.GridLayout(3, 3, 3, 3));

        jPanel12.setBorder(new javax.swing.border.TitledBorder("Intrinsic parameters"));
        eIPMatrix0.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        eIPMatrix0.setToolTipText("fx");
        jPanel12.add(eIPMatrix0);

        eIPMatrix1.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel12.add(eIPMatrix1);

        eIPMatrix2.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        eIPMatrix2.setToolTipText("cx");
        jPanel12.add(eIPMatrix2);

        eIPMatrix3.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel12.add(eIPMatrix3);

        eIPMatrix4.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        eIPMatrix4.setToolTipText("fy");
        jPanel12.add(eIPMatrix4);

        eIPMatrix5.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        eIPMatrix5.setToolTipText("cy");
        jPanel12.add(eIPMatrix5);

        eIPMatrix6.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel12.add(eIPMatrix6);

        eIPMatrix7.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel12.add(eIPMatrix7);

        eIPMatrix8.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel12.add(eIPMatrix8);

        pnlIPResults.add(jPanel12);

        jPanel13.setLayout(new java.awt.GridLayout(2, 4, 3, 3));

        jPanel13.setBorder(new javax.swing.border.TitledBorder("Distortion coefficients"));
        jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        jLabel1.setText("k1 =");
        jPanel13.add(jLabel1);

        eIPDistk1.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel13.add(eIPDistk1);

        lblIPDistp1.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        lblIPDistp1.setText("p1 =");
        jPanel13.add(lblIPDistp1);

        eIPDistp1.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel13.add(eIPDistp1);

        lblIPDistk2.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        lblIPDistk2.setText("k2 =");
        jPanel13.add(lblIPDistk2);

        eIPDistk2.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel13.add(eIPDistk2);

        jLabel4.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        jLabel4.setText("p2 =");
        jPanel13.add(jLabel4);

        eIPDistp2.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel13.add(eIPDistp2);

        pnlIPResults.add(jPanel13);

        jPanel16.setLayout(new javax.swing.BoxLayout(jPanel16, javax.swing.BoxLayout.Y_AXIS));

        jPanel16.setBorder(new javax.swing.border.TitledBorder("Configuration params format:"));
        jPanel17.setLayout(new java.awt.BorderLayout(3, 3));

        jPanel17.setBorder(new javax.swing.border.EtchedBorder());
        eIPConfigFmt.setFont(new java.awt.Font("Courier New", 0, 12));
        eIPConfigFmt.setLineWrap(true);
        eIPConfigFmt.setRows(6);
        jPanel17.add(eIPConfigFmt, java.awt.BorderLayout.CENTER);

        jPanel16.add(jPanel17);

        btnIP.setFont(new java.awt.Font("Dialog", 0, 10));
        btnIP.setText("Save as...");
        btnIP.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnIPActionPerformed(evt);
            }
        });

        jPanel16.add(btnIP);

        pnlIPResults.add(jPanel16);

        jPanel14.setPreferredSize(new java.awt.Dimension(10, 500));
        pnlIPResults.add(jPanel14);

        jtpIntCalOptions.addTab("Results", pnlIPResults);

        pnlIPUndistortedImage.setLayout(new javax.swing.BoxLayout(pnlIPUndistortedImage, javax.swing.BoxLayout.Y_AXIS));

        jPanel15.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT));

        jPanel15.setBorder(new javax.swing.border.EtchedBorder());
        jPanel15.setMaximumSize(new java.awt.Dimension(32767, 36));
        btnIPUndistortedLoad.setFont(new java.awt.Font("Dialog", 0, 10));
        btnIPUndistortedLoad.setText("Load distorted image...");
        btnIPUndistortedLoad.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnIPUndistortedLoadActionPerformed(evt);
            }
        });

        jPanel15.add(btnIPUndistortedLoad);

        btnIPUndistortedSaveAs.setFont(new java.awt.Font("Dialog", 0, 10));
        btnIPUndistortedSaveAs.setText("Save undistorted image as...");
        btnIPUndistortedSaveAs.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnIPUndistortedSaveAsActionPerformed(evt);
            }
        });

        jPanel15.add(btnIPUndistortedSaveAs);

        btnIPUndist.setFont(new java.awt.Font("Dialog", 0, 10));
        btnIPUndist.setText("View undistorted");
        btnIPUndist.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnIPUndistActionPerformed(evt);
            }
        });

        jPanel15.add(btnIPUndist);

        pnlIPUndistortedImage.add(jPanel15);

        jtpIntCalOptions.addTab("Test", pnlIPUndistortedImage);

        jPanel6.add(jtpIntCalOptions, java.awt.BorderLayout.CENTER);

        jSplitPane1.setRightComponent(jPanel6);

        jPanel1.add(jSplitPane1, java.awt.BorderLayout.CENTER);

        jTabbedPane1.addTab("Intrinsic calibration", jPanel1);

        jPanel3.setLayout(new java.awt.BorderLayout());

        jPanel18.setLayout(new javax.swing.BoxLayout(jPanel18, javax.swing.BoxLayout.Y_AXIS));

        jPanel18.setBorder(new javax.swing.border.TitledBorder("Correspondance points"));
        btnHMPointAddMode.setSelected(true);
        btnHMPointAddMode.setText("Add");
        jPanel20.add(btnHMPointAddMode);

        btnHMPointEdit.setText("Edit");
        btnHMPointEdit.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnHMPointEditActionPerformed(evt);
            }
        });

        jPanel20.add(btnHMPointEdit);

        btnHMPointDel.setText("Delete");
        btnHMPointDel.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnHMPointDelActionPerformed(evt);
            }
        });

        jPanel20.add(btnHMPointDel);

        jPanel18.add(jPanel20);

        jPanel33.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));

        jPanel33.setBorder(new javax.swing.border.EtchedBorder());
        jLabel2.setFont(new java.awt.Font("Dialog", 0, 10));
        jLabel2.setText("Image point ==> World point");
        jPanel33.add(jLabel2);

        jPanel18.add(jPanel33);

        jPanel21.setLayout(new java.awt.BorderLayout());

        lstHMPoints.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
        lstHMPoints.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyPressed(java.awt.event.KeyEvent evt) {
                lstHMPointsKeyPressed(evt);
            }
        });
        lstHMPoints.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
                lstHMPointsValueChanged(evt);
            }
        });
        lstHMPoints.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                lstHMPointsMouseClicked(evt);
            }
        });

        jScrollPane2.setViewportView(lstHMPoints);

        jPanel21.add(jScrollPane2, java.awt.BorderLayout.CENTER);

        jPanel18.add(jPanel21);

        btnHMGetMatrix.setForeground(new java.awt.Color(255, 0, 0));
        btnHMGetMatrix.setText("Calculate matrix");
        btnHMGetMatrix.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnHMGetMatrixActionPerformed(evt);
            }
        });

        jPanel24.add(btnHMGetMatrix);

        jPanel18.add(jPanel24);

        jSplitPane2.setLeftComponent(jPanel18);

        jPanel19.setLayout(new javax.swing.BoxLayout(jPanel19, javax.swing.BoxLayout.Y_AXIS));

        jtpHMOptions.setTabPlacement(javax.swing.JTabbedPane.BOTTOM);
        jPanel25.setLayout(new javax.swing.BoxLayout(jPanel25, javax.swing.BoxLayout.Y_AXIS));

        jPanel22.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT));

        jPanel22.setBorder(new javax.swing.border.EtchedBorder());
        jPanel22.setMaximumSize(new java.awt.Dimension(32767, 36));
        jPanel22.setMinimumSize(new java.awt.Dimension(246, 36));
        btnHMLoadUndistorted.setText("Load undistorted reference image...");
        btnHMLoadUndistorted.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnHMLoadUndistortedActionPerformed(evt);
            }
        });

        jPanel22.add(btnHMLoadUndistorted);

        jPanel25.add(jPanel22);

        pnlHMImageReference.setLayout(new java.awt.BorderLayout());

        pnlHMImageReference.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                pnlHMImageReferenceMouseClicked(evt);
            }
        });
        pnlHMImageReference.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
            public void mouseMoved(java.awt.event.MouseEvent evt) {
                pnlHMImageReferenceMouseMoved(evt);
            }
        });

        jPanel25.add(pnlHMImageReference);

        jPanel23.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT));

        jPanel23.setBorder(new javax.swing.border.EtchedBorder());
        jPanel23.setMaximumSize(new java.awt.Dimension(32767, 26));
        lblHMImgCoordinates.setFont(new java.awt.Font("Courier New", 0, 12));
        lblHMImgCoordinates.setText("(0,0)");
        jPanel23.add(lblHMImgCoordinates);

        jPanel25.add(jPanel23);

        jtpHMOptions.addTab("Points selection", jPanel25);

        jPanel26.setLayout(new javax.swing.BoxLayout(jPanel26, javax.swing.BoxLayout.Y_AXIS));

        jPanel28.setLayout(new java.awt.GridLayout(3, 3, 3, 3));

        jPanel28.setBorder(new javax.swing.border.TitledBorder("Homography matrix Image ==> World"));
        eHM0.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel28.add(eHM0);

        eHM1.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel28.add(eHM1);

        eHM2.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel28.add(eHM2);

        eHM3.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel28.add(eHM3);

        eHM4.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel28.add(eHM4);

        eHM5.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel28.add(eHM5);

        eHM6.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel28.add(eHM6);

        eHM7.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel28.add(eHM7);

        eHM8.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel28.add(eHM8);

        jPanel26.add(jPanel28);

        jPanel32.setLayout(new java.awt.GridLayout(3, 3, 3, 3));

        jPanel32.setBorder(new javax.swing.border.TitledBorder("Homography matrix World ==> Image"));
        eHM_w2i_0.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel32.add(eHM_w2i_0);

        eHM_w2i_1.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel32.add(eHM_w2i_1);

        eHM_w2i_2.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel32.add(eHM_w2i_2);

        eHM_w2i_3.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel32.add(eHM_w2i_3);

        eHM_w2i_4.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel32.add(eHM_w2i_4);

        eHM_w2i_5.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel32.add(eHM_w2i_5);

        eHM_w2i_6.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel32.add(eHM_w2i_6);

        eHM_w2i_7.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel32.add(eHM_w2i_7);

        eHM_w2i_8.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        jPanel32.add(eHM_w2i_8);

        jPanel26.add(jPanel32);

        jPanel29.setLayout(new javax.swing.BoxLayout(jPanel29, javax.swing.BoxLayout.Y_AXIS));

        jPanel29.setBorder(new javax.swing.border.TitledBorder("Configuration params format"));
        jPanel31.setLayout(new java.awt.BorderLayout());

        jPanel31.setBorder(new javax.swing.border.EtchedBorder());
        eHMConfigFmt.setFont(new java.awt.Font("Courier New", 0, 12));
        eHMConfigFmt.setLineWrap(true);
        eHMConfigFmt.setRows(15);
        jPanel31.add(eHMConfigFmt, java.awt.BorderLayout.CENTER);

        jPanel29.add(jPanel31);

        btnHMSaveMatrix.setFont(new java.awt.Font("Dialog", 0, 10));
        btnHMSaveMatrix.setText("Save as...");
        btnHMSaveMatrix.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnHMSaveMatrixActionPerformed(evt);
            }
        });

        jPanel29.add(btnHMSaveMatrix);

        jPanel26.add(jPanel29);

        jPanel30.setPreferredSize(new java.awt.Dimension(10, 1000));
        jPanel26.add(jPanel30);

        jtpHMOptions.addTab("Results", jPanel26);

        jPanel27.setLayout(new javax.swing.BoxLayout(jPanel27, javax.swing.BoxLayout.Y_AXIS));

        pnlHMTestMode.setLayout(new java.awt.BorderLayout());

        pnlHMTestMode.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
            public void mouseMoved(java.awt.event.MouseEvent evt) {
                pnlHMTestModeMouseMoved(evt);
            }
        });

        jPanel27.add(pnlHMTestMode);

        jPanel35.setLayout(new java.awt.GridLayout(1, 2, 10, 10));

        jPanel35.setBorder(new javax.swing.border.CompoundBorder(new javax.swing.border.EtchedBorder(), new javax.swing.border.EmptyBorder(new java.awt.Insets(3, 3, 3, 3))));
        jPanel35.setMaximumSize(new java.awt.Dimension(32767, 16));
        lblHMTestImagePoint.setFont(new java.awt.Font("Courier New", 0, 12));
        lblHMTestImagePoint.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
        lblHMTestImagePoint.setText("(0,0)");
        lblHMTestImagePoint.setToolTipText("Image point");
        jPanel35.add(lblHMTestImagePoint);

        lblHMTestWorldPoint.setFont(new java.awt.Font("Courier New", 0, 12));
        lblHMTestWorldPoint.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        lblHMTestWorldPoint.setText("(0,0)");
        lblHMTestWorldPoint.setToolTipText("World point");
        jPanel35.add(lblHMTestWorldPoint);

        jPanel27.add(jPanel35);

        jtpHMOptions.addTab("Test mode", jPanel27);

        jPanel34.setLayout(new javax.swing.BoxLayout(jPanel34, javax.swing.BoxLayout.Y_AXIS));

        pnlHMImageProjection.setLayout(new java.awt.BorderLayout());

        jPanel34.add(pnlHMImageProjection);

        jPanel37.setLayout(new javax.swing.BoxLayout(jPanel37, javax.swing.BoxLayout.X_AXIS));

        jPanel37.setMaximumSize(new java.awt.Dimension(32767, 16));
        jPanel36.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));

        jLabel6.setFont(new java.awt.Font("Dialog", 0, 10));
        jLabel6.setText("Origin:");
        jPanel36.add(jLabel6);

        cbxHMImgProjectionOrigin.setFont(new java.awt.Font("Dialog", 0, 10));
        cbxHMImgProjectionOrigin.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "L-U", "R-U", "R-B", "L-B" }));
        cbxHMImgProjectionOrigin.setSelectedIndex(3);
        cbxHMImgProjectionOrigin.setToolTipText("[Left|Rigth]-[Top-Bottom]");
        jPanel36.add(cbxHMImgProjectionOrigin);

        jLabel3.setFont(new java.awt.Font("Dialog", 0, 10));
        jLabel3.setText("Scale: 1px =");
        jPanel36.add(jLabel3);

        eHMImageProjectionScale.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        eHMImageProjectionScale.setText("0.01");
        eHMImageProjectionScale.setPreferredSize(new java.awt.Dimension(60, 20));
        jPanel36.add(eHMImageProjectionScale);

        jLabel5.setFont(new java.awt.Font("Dialog", 0, 10));
        jLabel5.setText("Coordinates:");
        jPanel36.add(jLabel5);

        eHMImgProjectorX1.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        eHMImgProjectorX1.setText("0");
        eHMImgProjectorX1.setToolTipText("x1");
        eHMImgProjectorX1.setPreferredSize(new java.awt.Dimension(45, 20));
        jPanel36.add(eHMImgProjectorX1);

        eHMImgProjectorY1.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        eHMImgProjectorY1.setText("0");
        eHMImgProjectorY1.setToolTipText("y1");
        eHMImgProjectorY1.setPreferredSize(new java.awt.Dimension(45, 20));
        jPanel36.add(eHMImgProjectorY1);

        eHMImgProjectorX2.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        eHMImgProjectorX2.setToolTipText("x2");
        eHMImgProjectorX2.setPreferredSize(new java.awt.Dimension(45, 20));
        jPanel36.add(eHMImgProjectorX2);

        eHMImgProjectorY2.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        eHMImgProjectorY2.setToolTipText("y2");
        eHMImgProjectorY2.setPreferredSize(new java.awt.Dimension(45, 20));
        jPanel36.add(eHMImgProjectorY2);

        btnHMImageProjScaleGenerate.setFont(new java.awt.Font("Dialog", 0, 10));
        btnHMImageProjScaleGenerate.setText("Generate");
        btnHMImageProjScaleGenerate.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnHMImageProjScaleGenerateActionPerformed(evt);
            }
        });

        jPanel36.add(btnHMImageProjScaleGenerate);

        jPanel37.add(jPanel36);

        jPanel38.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT));

        btnHMImageProjScaleApply1.setFont(new java.awt.Font("Dialog", 0, 10));
        btnHMImageProjScaleApply1.setText("Save image...");
        btnHMImageProjScaleApply1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnHMImageProjScaleApply1ActionPerformed(evt);
            }
        });

        jPanel38.add(btnHMImageProjScaleApply1);

        jPanel37.add(jPanel38);

        jPanel34.add(jPanel37);

        jtpHMOptions.addTab("Image projection", jPanel34);

        jPanel19.add(jtpHMOptions);

        jSplitPane2.setRightComponent(jPanel19);

        jPanel3.add(jSplitPane2, java.awt.BorderLayout.CENTER);

        jTabbedPane1.addTab("Homography matrix", jPanel3);

        jTabbedPane1.addTab("Camera setup", jPanel4);

        getContentPane().add(jTabbedPane1);

        jPanel2.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT));

        jPanel2.setBorder(new javax.swing.border.EmptyBorder(new java.awt.Insets(3, 3, 3, 3)));
        jButton1.setText("About...");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        jPanel2.add(jButton1);

        jButton2.setText("Exit");
        jButton2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton2ActionPerformed(evt);
            }
        });

        jPanel2.add(jButton2);

        getContentPane().add(jPanel2);

        java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        setBounds((screenSize.width-1000)/2, (screenSize.height-680)/2, 1000, 680);
    }//GEN-END:initComponents

	//----------------------------------------------------------------------------------
	private void btnHMImageProjScaleApply1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnHMImageProjScaleApply1ActionPerformed
		// Add your handling code here:
		String complete = "";
		jfci.setDialogTitle("Save projected image as...");
		if (jfci.showSaveDialog(this) == JFileChooser.APPROVE_OPTION){
			complete = jfci.getSelectedFile().getParent() + File.separatorChar + jfci.getSelectedFile().getName();
			JPEGFileManager.saveFile(this.ips.getImage(), complete, 100);
		}
	}//GEN-LAST:event_btnHMImageProjScaleApply1ActionPerformed

	//----------------------------------------------------------------------------------
	private void btnHMImageProjScaleGenerateActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnHMImageProjScaleGenerateActionPerformed
		// Add your handling code here:
		double[] values = new double[5];
		javax.swing.JTextField fields[] = {this.eHMImageProjectionScale, this.eHMImgProjectorX1, this.eHMImgProjectorY1, this.eHMImgProjectorX2, this.eHMImgProjectorY2};

		for (int i=0; i<5; i++){
			if (fields[i].getText() == ""){
				fields[i].grabFocus();
				return;
			}
			try{
				values[i] = new Double(fields[i].getText()).doubleValue();
			}
			catch(NumberFormatException e){
				fields[i].grabFocus();
				return;
			}
		}
		this.hip = new HomographyImageProjection(this.homoI2W,  this.homoW2I, this.chomoip.getImage());
		this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
		BufferedImage theres = this.hip.process(values[0], values[1], values[2], values[3], values[4], this.cbxHMImgProjectionOrigin.getSelectedIndex()+1);
		this.setCursor(Cursor.getDefaultCursor());
		if (theres != null){
			this.ips.setImage(theres);
		}
		else{
			JOptionPane.showMessageDialog(this, "Unable to create the projection image. Try to reduce the scale.", "ERROR", JOptionPane.ERROR_MESSAGE);	
		}
	}//GEN-LAST:event_btnHMImageProjScaleGenerateActionPerformed

	//----------------------------------------------------------------------------------
	private void pnlHMTestModeMouseMoved(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_pnlHMTestModeMouseMoved
		// Add your handling code here:
		Point mouse = new Point((int)evt.getX(), (int)evt.getY());
		DecimalFormat fmt = new DecimalFormat("0.00000");
		if (mouse.x < this.fw && mouse.y < this.fh){
			this.lblHMTestImagePoint.setText("Image point = (" + mouse.x + ", " + mouse.y + ")");
			PointDouble real = this.homoTrans.image2World(mouse.x, mouse.y);
			this.lblHMTestWorldPoint.setText("World point = (" + fmt.format(real.x) + ", " + fmt.format(real.y) + ")");
		}
	}//GEN-LAST:event_pnlHMTestModeMouseMoved

	//----------------------------------------------------------------------------------
	private void lstHMPointsMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_lstHMPointsMouseClicked
		// Add your handling code here:
		if (this.jtpHMOptions.getSelectedIndex() != 0) this.jtpHMOptions.setSelectedIndex(0);
		if (evt.getClickCount() == 2){
			this.btnHMPointEditActionPerformed(null);
		}
	}//GEN-LAST:event_lstHMPointsMouseClicked

	//----------------------------------------------------------------------------------
	private void btnHMSaveMatrixActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnHMSaveMatrixActionPerformed
		// Add your handling code here:
		JFileChooser jfc = new JFileChooser();
		String complete = "";
		jfc.setDialogTitle("Save parameters as...");
		if (jfc.showSaveDialog(this) == JFileChooser.APPROVE_OPTION){
			complete = jfc.getSelectedFile().getParent() + File.separatorChar + jfc.getSelectedFile().getName();
			try{
				FileWriter fw = new FileWriter(complete, false);
				fw.write(this.eHMConfigFmt.getText());
				fw.close();
			}
			catch (Exception e){
				System.out.println("btnHMSaveMatrixActionPerformed : Error saving the file: " + complete);
				e.printStackTrace();
			}
		}
	}//GEN-LAST:event_btnHMSaveMatrixActionPerformed

	//----------------------------------------------------------------------------------
	private void btnHMPointEditActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnHMPointEditActionPerformed
		// Add your handling code here:
		if (this.lstHMPoints.getSelectedIndex() != -1){
			int indx = this.lstHMPoints.getSelectedIndex();
			PointImageWorld piw = (PointImageWorld)this.lstHomoPoints.get(indx);
			Point2D imgPoint = piw.getImagePoint();
			Rectangle sub = new Rectangle((int)imgPoint.getX()-this.subImageSize/2, 
			                              (int)imgPoint.getY()-this.subImageSize/2, 
			                              this.subImageSize , this.subImageSize);
			BufferedImage subImg = ImageTools.getZoomedImage(this.chomoip.getImage(), sub, this.scaleHomoPoint);
			HMWorldCoordinatesDialog wcd = new HMWorldCoordinatesDialog(this, true, piw.getImagePoint(), piw.getWorldPoint(), sub, this.scaleHomoPoint, subImg, this.chomoip.getImage().getWidth(), this.chomoip.getImage().getHeight());
			Toolkit tk = Toolkit.getDefaultToolkit();
			int scrWidth = (int)tk.getScreenSize().getWidth();
			int scrHeigth = (int)tk.getScreenSize().getHeight();
			int wcdx = (int)(piw.getImagePoint().getX() + this.chomoip.getLocationOnScreen().getX() + 5);
			int wcdy = (int)(piw.getImagePoint().getY() + this.chomoip.getLocationOnScreen().getY() + 5);
			wcdx = wcdx + wcd.getWidth() > scrWidth ? scrWidth - wcd.getWidth() : wcdx;
			wcdy = wcdy + wcd.getHeight() > scrHeigth ? scrHeigth - wcd.getHeight() : wcdy;
			wcd.setLocation(wcdx, wcdy);
			wcd.show();
			if (wcd.getResult()){
				piw.setWorldPoint(wcd.getWorldX(),  wcd.getWorldY());
				piw.setImagePoint(wcd.getImageX(),  wcd.getImageX());
				this.lstHMPoints.repaint();
			}
		}
	}//GEN-LAST:event_btnHMPointEditActionPerformed

	//----------------------------------------------------------------------------------
	private void btnHMPointDelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnHMPointDelActionPerformed
		// Add your handling code here:
		if (this.lstHMPoints.getSelectedIndex() != -1){
			int idx = this.lstHMPoints.getSelectedIndex();
			this.lstHomoPoints.remove(idx);
			this.chomoip.deletePoint(idx);
		}
	}//GEN-LAST:event_btnHMPointDelActionPerformed

	//----------------------------------------------------------------------------------
	private void lstHMPointsKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_lstHMPointsKeyPressed
		// Add your handling code here:
		if (evt.getKeyCode() == evt.VK_DELETE){
			this.btnHMPointDelActionPerformed(null);
		}
	}//GEN-LAST:event_lstHMPointsKeyPressed

	//----------------------------------------------------------------------------------
	private void btnHMGetMatrixActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnHMGetMatrixActionPerformed
		// Add your handling code here:
		if (this.lstHomoPoints.size() < 5){
			JOptionPane.showMessageDialog(this, "You need at least 5 points to calculate the homography matrix.");
		}
		else{
			int size = this.lstHomoPoints.size() * 2;
			double imagePoints[] = new double[size];
			double worldPoints[] = new double[size];
			for (int i=0, j=0; i<size; i+=2, j++){
				PointImageWorld pnt = (PointImageWorld)this.lstHomoPoints.get(j);
				imagePoints[i]   = pnt.getImageX();
				imagePoints[i+1] = pnt.getImageY();
				worldPoints[i]   = pnt.getWorldX();
				worldPoints[i+1] = pnt.getWorldY();
			}
			homoI2W = this.cocv.getHomographyMatrix(imagePoints, worldPoints, size/2, this.fw, this.fh);
			this.eHM0.setText(Double.toString(homoI2W[0]));
			this.eHM1.setText(Double.toString(homoI2W[1]));
			this.eHM2.setText(Double.toString(homoI2W[2]));
			this.eHM3.setText(Double.toString(homoI2W[3]));
			this.eHM4.setText(Double.toString(homoI2W[4]));
			this.eHM5.setText(Double.toString(homoI2W[5]));
			this.eHM6.setText(Double.toString(homoI2W[6]));
			this.eHM7.setText(Double.toString(homoI2W[7]));
			this.eHM8.setText(Double.toString(homoI2W[8]));
			this.eHMConfigFmt.setText("");
			String txt = "WIP_HOMO_IMG2WRLD = ";
			for(int i=0; i<9; i++) txt += homoI2W[i] + " ";
			
			homoW2I = this.cocv.getHomographyMatrix(worldPoints, imagePoints, size/2, this.fw, this.fh);
			this.eHM_w2i_0.setText(Double.toString(homoW2I[0]));
			this.eHM_w2i_1.setText(Double.toString(homoW2I[1]));
			this.eHM_w2i_2.setText(Double.toString(homoW2I[2]));
			this.eHM_w2i_3.setText(Double.toString(homoW2I[3]));
			this.eHM_w2i_4.setText(Double.toString(homoW2I[4]));
			this.eHM_w2i_5.setText(Double.toString(homoW2I[5]));
			this.eHM_w2i_6.setText(Double.toString(homoW2I[6]));
			this.eHM_w2i_7.setText(Double.toString(homoW2I[7]));
			this.eHM_w2i_8.setText(Double.toString(homoW2I[8]));
			txt += "\nWIP_HOMO_WRLD2IMG = ";
			for(int i=0; i<9; i++) txt += homoW2I[i] + " ";
			this.eHMConfigFmt.setText(txt);
			this.jtpHMOptions.setSelectedIndex(1);
			
			this.homoTrans = new HomographyTransform(homoW2I, homoI2W);
			
			this.chomoipTest.setImage(this.chomoip.getImage());
			this.chomoipTest.setPoints(this.chomoip.getPoints());
			this.chomoipTest.setSelectedPoint(-1);
		}
	}//GEN-LAST:event_btnHMGetMatrixActionPerformed

	//----------------------------------------------------------------------------------
	private void pnlHMImageReferenceMouseMoved(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_pnlHMImageReferenceMouseMoved
		// Add your handling code here:
		Point mouse = new Point((int)evt.getX(), (int)evt.getY());
		if (mouse.x < this.fw && mouse.y < this.fh){
			this.lblHMImgCoordinates.setText("(" + mouse.x + ", " + mouse.y + ")");
		}
	}//GEN-LAST:event_pnlHMImageReferenceMouseMoved

	//----------------------------------------------------------------------------------
	private void pnlHMImageReferenceMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_pnlHMImageReferenceMouseClicked
		// Add your handling code here:
		Point mouse = new Point((int)evt.getX(), (int)evt.getY());
		if (mouse.x < this.fw && mouse.y < this.fh){
			if (this.btnHMPointAddMode.isSelected()){
				Rectangle sub = new Rectangle(mouse.x-this.subImageSize/2, mouse.y-this.subImageSize/2, this.subImageSize , this.subImageSize);
				BufferedImage subImg = ImageTools.getZoomedImage(this.chomoip.getImage(), sub, this.scaleHomoPoint);
				HMWorldCoordinatesDialog wcd = new HMWorldCoordinatesDialog(this, true, mouse, new Point2D.Double(), sub, this.scaleHomoPoint, subImg, this.chomoip.getImage().getWidth(), this.chomoip.getImage().getHeight());
				Toolkit tk = Toolkit.getDefaultToolkit();
				int scrWidth = (int)tk.getScreenSize().getWidth();
				int scrHeigth = (int)tk.getScreenSize().getHeight();
				int wcdx = (int)(mouse.x + this.chomoip.getLocationOnScreen().getX() + 5);
				int wcdy = (int)(mouse.y + this.chomoip.getLocationOnScreen().getY() + 5);
				wcdx = wcdx + wcd.getWidth() > scrWidth ? scrWidth - wcd.getWidth() : wcdx;
				wcdy = wcdy + wcd.getHeight() > scrHeigth ? scrHeigth - wcd.getHeight() : wcdy;
				wcd.setLocation(wcdx, wcdy);
				wcd.show();
				if (wcd.getResult()){
					PointImageWorld piw = new PointImageWorld(wcd.getImageX(), wcd.getImageY(), wcd.getWorldX(), wcd.getWorldY());
					this.lstHomoPoints.addElement(piw);
					this.chomoip.addPoint(new Point((int)Math.round(wcd.getImageX()), (int)Math.round(wcd.getImageY())));
				}
			}
			else{
				this.chomoip.selectNearestPoint(mouse);
				this.lstHMPoints.setSelectedIndex(this.chomoip.getSelectedPoint());
			}
		}
	}//GEN-LAST:event_pnlHMImageReferenceMouseClicked

	//----------------------------------------------------------------------------------
	private void lstHMPointsValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_lstHMPointsValueChanged
		// Add your handling code here:
		this.chomoip.setSelectedPoint(this.lstHMPoints.getSelectedIndex());
	}//GEN-LAST:event_lstHMPointsValueChanged

	//----------------------------------------------------------------------------------
	private void btnHMLoadUndistortedActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnHMLoadUndistortedActionPerformed
		// Add your handling code here:
		String complete = "";
		jfci.setDialogTitle("Select undistorted reference image...");
		if (jfci.showOpenDialog(this) == JFileChooser.APPROVE_OPTION){
			complete = jfci.getSelectedFile().getParent() + File.separatorChar + jfci.getSelectedFile().getName();
			BufferedImage magic = ImageTools.convertGrayScaletoRGB(JPEGFileManager.openFile(complete));
			this.chomoip.setImage(magic);
			this.fw = magic.getWidth();
			this.fh = magic.getHeight();
		}
	}//GEN-LAST:event_btnHMLoadUndistortedActionPerformed

	//----------------------------------------------------------------------------------
	private void btnIPActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnIPActionPerformed
		// Add your handling code here:
		JFileChooser jfc = new JFileChooser();
		String complete = "";
		jfc.setDialogTitle("Save parameters as...");
		if (jfc.showSaveDialog(this) == JFileChooser.APPROVE_OPTION){
			complete = jfc.getSelectedFile().getParent() + File.separatorChar + jfc.getSelectedFile().getName();
			try{
				FileWriter fw = new FileWriter(complete, false);
				fw.write(this.eIPConfigFmt.getText());
				fw.close();
			}
			catch (Exception e){
				System.out.println("btnIPActionPerformed : Error saving the file: " + complete);
				e.printStackTrace();
			}
		}
	}//GEN-LAST:event_btnIPActionPerformed

	//----------------------------------------------------------------------------------
	private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
		// Add your handling code here:
		JOptionPane.showMessageDialog(this, "This program is free software (GPL).\nUses Intel Open Computer Vision Library (OpenCV).\n\n(2004) Hugo Ortega H. hugorteg@yahoo.com\nUtility for my thesis: \"Visual Tracking of Multiple Objects \nwith Mobile Camera in Dynamic Environments\"", "JCamCalib v0.7: A camera Calibration Utility", JOptionPane.INFORMATION_MESSAGE);
	}//GEN-LAST:event_jButton1ActionPerformed

	//----------------------------------------------------------------------------------
	private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed
		// Add your handling code here:
		System.exit(0);
	}//GEN-LAST:event_jButton2ActionPerformed

	//----------------------------------------------------------------------------------
	private void btnIPUndistActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnIPUndistActionPerformed
		// Add your handling code here:
		if (this.btnIPUndist.isSelected()){
			this.cipUndistored.setImage(this.undistorted);
		}
		else{
			this.cipUndistored.setImage(this.distorted);
		}
	}//GEN-LAST:event_btnIPUndistActionPerformed

	//----------------------------------------------------------------------------------
	private void btnIPUndistortedSaveAsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnIPUndistortedSaveAsActionPerformed
		// Add your handling code here:
		String complete = "";
		jfci.setDialogTitle("Save undistorted image as...");
		if (jfci.showSaveDialog(this) == JFileChooser.APPROVE_OPTION){
			complete = jfci.getSelectedFile().getParent() + File.separatorChar + jfci.getSelectedFile().getName();
			JPEGFileManager.saveFile(this.undistorted, complete, 100);
		}
	}//GEN-LAST:event_btnIPUndistortedSaveAsActionPerformed

	//----------------------------------------------------------------------------------
	private void btnIPUndistortedLoadActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnIPUndistortedLoadActionPerformed
		// Add your handling code here:
		String complete = "";
		jfci.setDialogTitle("Select distorted image...");
		if (jfci.showOpenDialog(this) == JFileChooser.APPROVE_OPTION){
			complete = jfci.getSelectedFile().getParent() + File.separatorChar + jfci.getSelectedFile().getName();
			BufferedImage magic = ImageTools.convertGrayScaletoRGB(JPEGFileManager.openFile(complete));
			BufferedImage undist = ImageTools.getBufferedImage(this.cocv.getUndistortedImage(ImageTools.getImageDataRGB(magic), magic.getWidth(), magic.getHeight()), magic.getWidth(), magic.getHeight());
			this.cipUndistored.setImage(undist);
			this.btnIPUndist.setSelected(true);
			this.undistorted = undist;
			this.distorted = magic;
		}
	}//GEN-LAST:event_btnIPUndistortedLoadActionPerformed

	//----------------------------------------------------------------------------------
	private void btnIPComputeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnIPComputeActionPerformed
		// Add your handling code here:
		for(int i=0; i<this.imagesCalib.size(); i++){
			BufferedImage magic = (BufferedImage)this.imagesCalib.get(i);
			this.cocv.addCalibrationImage(ImageTools.getImageDataRGB(magic), magic.getWidth(), magic.getHeight());
		}
		if (!this.cocv.calibrate()){
			JOptionPane.showMessageDialog(this, "Error in calibration. Try other images please.", "ERROR", JOptionPane.ERROR_MESSAGE);
		}
		else{
			double res[] = this.cocv.getResults();
			//for (int j=0; j<res.length; j++) System.out.println(res[j]);
			this.eIPMatrix0.setText(Double.toString(res[0]));
			this.eIPMatrix1.setText(Double.toString(res[1]));
			this.eIPMatrix2.setText(Double.toString(res[2]));
			this.eIPMatrix3.setText(Double.toString(res[3]));
			this.eIPMatrix4.setText(Double.toString(res[4]));
			this.eIPMatrix5.setText(Double.toString(res[5]));
			this.eIPMatrix6.setText(Double.toString(res[6]));
			this.eIPMatrix7.setText(Double.toString(res[7]));
			this.eIPMatrix8.setText(Double.toString(res[8]));
			this.eIPDistk1.setText(Double.toString(res[9]));
			this.eIPDistk2.setText(Double.toString(res[10]));
			this.eIPDistp1.setText(Double.toString(res[11]));
			this.eIPDistp2.setText(Double.toString(res[12]));
			this.jtpIntCalOptions.setSelectedIndex(1);
			this.eIPConfigFmt.setText("");
			String txt = "CAMERA_INTRINSICS = ";
			for(int i=0; i<9; i++) txt += res[i] + " ";
			txt += "\nCAMERA_LENS_DIST = ";
			for(int i=9; i<13; i++) txt += res[i] + " ";
			
			this.eIPConfigFmt.setText(txt);
		}
	}//GEN-LAST:event_btnIPComputeActionPerformed

	//----------------------------------------------------------------------------------
	private void btnIPDelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnIPDelActionPerformed
		// Add your handling code here:
		if (this.lstImgsCalib.size() > 0){
			int idx = this.lstImagesCalib.getSelectedIndex();
			this.lstImgsCalib.remove(idx);
			this.imagesCalib.remove(idx);
			if (this.lstImgsCalib.size() > 0) this.lstImagesCalib.setSelectedIndex(this.lstImgsCalib.size()-1);
		}
	}//GEN-LAST:event_btnIPDelActionPerformed

	//----------------------------------------------------------------------------------
	private void lstImagesCalibValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_lstImagesCalibValueChanged
		// Add your handling code here:
		if (this.lstImgsCalib.size() > 0 && this.lstImagesCalib.getSelectedIndex() >= 0){
			if (this.jtpIntCalOptions.getSelectedIndex() != 0) this.jtpIntCalOptions.setSelectedIndex(0);
			BufferedImage magic = (BufferedImage)this.imagesCalib.get(this.lstImagesCalib.getSelectedIndex());
			this.cip.clearPoints();
			this.cip.setImage(magic);
			double pnts[] = this.cocv.findCorners(ImageTools.getImageDataRGB(magic), fw,  fh);
			if (pnts == null){
				JOptionPane.showMessageDialog(this, "Chessboard pattern was not detected in this image. Try increasing contrast of image and reduce the brightness.");
				return;
			}
			else if (pnts.length != 96){
				JOptionPane.showMessageDialog(this, "Not all points in the chessboard pattern were detected in this image. Try to use an image with better illumination or resolution please.", "ERROR", JOptionPane.ERROR_MESSAGE);
			}

			for (int i=0; i<pnts.length; i+=2){
				this.cip.addPoint((int)Math.round(pnts[i]), (int)Math.round(pnts[i+1]));
			}
			this.cip.repaint();
		}
	}//GEN-LAST:event_lstImagesCalibValueChanged

	//----------------------------------------------------------------------------------
	private void btnIPAddFromCameraActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnIPAddFromCameraActionPerformed
		// Add your handling code here:
	}//GEN-LAST:event_btnIPAddFromCameraActionPerformed

	//----------------------------------------------------------------------------------
	private void btnIPAddFromFileActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnIPAddFromFileActionPerformed
		// Add your handling code here:
		String complete = "";
		jfci.setDialogTitle("Select a calibration image...");
		if (jfci.showOpenDialog(this) == JFileChooser.APPROVE_OPTION){
			complete = jfci.getSelectedFile().getParent() + File.separatorChar + jfci.getSelectedFile().getName();
			BufferedImage magic = ImageTools.convertGrayScaletoRGB(JPEGFileManager.openFile(complete));
			//this.pnlIPCalibrationImage.setSize(magic.getWidth(), magic.getHeight());
			if (this.imagesCalib.size() == 0){
				this.fw = magic.getWidth();
				this.fh = magic.getHeight();
			}
			if (magic.getWidth() != this.fw || magic.getHeight() != this.fh){
				JOptionPane.showMessageDialog(this, "Image is not valid: should be same size of the first one (" + this.fw + "x" + this.fh + ")", "ERROR", JOptionPane.ERROR_MESSAGE);
			}
			else{
				this.imagesCalib.add(magic);
				this.lstImgsCalib.addElement(complete);
				this.lstImagesCalib.setSelectedIndex(this.lstImgsCalib.size()-1);
			}
		}
	}//GEN-LAST:event_btnIPAddFromFileActionPerformed
	
	//----------------------------------------------------------------------------------
	/** Exit the Application */
	private void exitForm(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_exitForm
		System.exit(0);
	}//GEN-LAST:event_exitForm

	//----------------------------------------------------------------------------------
	/**
	 * @param args the command line arguments
	 */
	public static void main(String args[]) {
		try {
			UIManager.setLookAndFeel("ch.randelshofer.quaqua.QuaquaLookAndFeel");
		}
		catch (Exception e){
			System.out.println("Unable to load Look and Feel... using default Metal.");
		}		
		new JCamCalib().show();
	}
	
	
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btnHMGetMatrix;
    private javax.swing.JButton btnHMImageProjScaleApply1;
    private javax.swing.JButton btnHMImageProjScaleGenerate;
    private javax.swing.JButton btnHMLoadUndistorted;
    private javax.swing.JToggleButton btnHMPointAddMode;
    private javax.swing.JButton btnHMPointDel;
    private javax.swing.JButton btnHMPointEdit;
    private javax.swing.JButton btnHMSaveMatrix;
    private javax.swing.JButton btnIP;
    private javax.swing.JButton btnIPAddFromCamera;
    private javax.swing.JButton btnIPAddFromFile;
    private javax.swing.JButton btnIPCompute;
    private javax.swing.JButton btnIPDel;
    private javax.swing.JToggleButton btnIPUndist;
    private javax.swing.JButton btnIPUndistortedLoad;
    private javax.swing.JButton btnIPUndistortedSaveAs;
    private javax.swing.JComboBox cbxHMImgProjectionOrigin;
    private javax.swing.JTextField eHM0;
    private javax.swing.JTextField eHM1;
    private javax.swing.JTextField eHM2;
    private javax.swing.JTextField eHM3;
    private javax.swing.JTextField eHM4;
    private javax.swing.JTextField eHM5;
    private javax.swing.JTextField eHM6;
    private javax.swing.JTextField eHM7;
    private javax.swing.JTextField eHM8;
    private javax.swing.JTextArea eHMConfigFmt;
    private javax.swing.JTextField eHMImageProjectionScale;
    private javax.swing.JTextField eHMImgProjectorX1;
    private javax.swing.JTextField eHMImgProjectorX2;
    private javax.swing.JTextField eHMImgProjectorY1;
    private javax.swing.JTextField eHMImgProjectorY2;
    private javax.swing.JTextField eHM_w2i_0;
    private javax.swing.JTextField eHM_w2i_1;
    private javax.swing.JTextField eHM_w2i_2;
    private javax.swing.JTextField eHM_w2i_3;
    private javax.swing.JTextField eHM_w2i_4;
    private javax.swing.JTextField eHM_w2i_5;
    private javax.swing.JTextField eHM_w2i_6;
    private javax.swing.JTextField eHM_w2i_7;
    private javax.swing.JTextField eHM_w2i_8;
    private javax.swing.JTextArea eIPConfigFmt;
    private javax.swing.JTextField eIPDistk1;
    private javax.swing.JTextField eIPDistk2;
    private javax.swing.JTextField eIPDistp1;
    private javax.swing.JTextField eIPDistp2;
    private javax.swing.JTextField eIPMatrix0;
    private javax.swing.JTextField eIPMatrix1;
    private javax.swing.JTextField eIPMatrix2;
    private javax.swing.JTextField eIPMatrix3;
    private javax.swing.JTextField eIPMatrix4;
    private javax.swing.JTextField eIPMatrix5;
    private javax.swing.JTextField eIPMatrix6;
    private javax.swing.JTextField eIPMatrix7;
    private javax.swing.JTextField eIPMatrix8;
    private javax.swing.JButton jButton1;
    private javax.swing.JButton jButton2;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel jLabel6;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel10;
    private javax.swing.JPanel jPanel11;
    private javax.swing.JPanel jPanel12;
    private javax.swing.JPanel jPanel13;
    private javax.swing.JPanel jPanel14;
    private javax.swing.JPanel jPanel15;
    private javax.swing.JPanel jPanel16;
    private javax.swing.JPanel jPanel17;
    private javax.swing.JPanel jPanel18;
    private javax.swing.JPanel jPanel19;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel20;
    private javax.swing.JPanel jPanel21;
    private javax.swing.JPanel jPanel22;
    private javax.swing.JPanel jPanel23;
    private javax.swing.JPanel jPanel24;
    private javax.swing.JPanel jPanel25;
    private javax.swing.JPanel jPanel26;
    private javax.swing.JPanel jPanel27;
    private javax.swing.JPanel jPanel28;
    private javax.swing.JPanel jPanel29;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JPanel jPanel30;
    private javax.swing.JPanel jPanel31;
    private javax.swing.JPanel jPanel32;
    private javax.swing.JPanel jPanel33;
    private javax.swing.JPanel jPanel34;
    private javax.swing.JPanel jPanel35;
    private javax.swing.JPanel jPanel36;
    private javax.swing.JPanel jPanel37;
    private javax.swing.JPanel jPanel38;
    private javax.swing.JPanel jPanel4;
    private javax.swing.JPanel jPanel5;
    private javax.swing.JPanel jPanel6;
    private javax.swing.JPanel jPanel7;
    private javax.swing.JPanel jPanel8;
    private javax.swing.JPanel jPanel9;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JSplitPane jSplitPane1;
    private javax.swing.JSplitPane jSplitPane2;
    private javax.swing.JTabbedPane jTabbedPane1;
    private javax.swing.JTabbedPane jtpHMOptions;
    private javax.swing.JTabbedPane jtpIntCalOptions;
    private javax.swing.JLabel lblHMImgCoordinates;
    private javax.swing.JLabel lblHMTestImagePoint;
    private javax.swing.JLabel lblHMTestWorldPoint;
    private javax.swing.JLabel lblIPDistk2;
    private javax.swing.JLabel lblIPDistp1;
    private javax.swing.JList lstHMPoints;
    private javax.swing.JList lstImagesCalib;
    private javax.swing.JPanel pnlHMImageProjection;
    private javax.swing.JPanel pnlHMImageReference;
    private javax.swing.JPanel pnlHMTestMode;
    private javax.swing.JPanel pnlIPCalibrationImages;
    private javax.swing.JPanel pnlIPResults;
    private javax.swing.JPanel pnlIPUndistortedImage;
    // End of variables declaration//GEN-END:variables
	private DefaultListModel lstImgsCalib = new DefaultListModel();
	private DefaultListModel lstHomoPoints = new DefaultListModel();
	private FileChooserImage jfci = new FileChooserImage();
	private CalibratorImagePanel cip = new CalibratorImagePanel();
	private CalibratorImagePanel cipUndistored = new CalibratorImagePanel();
	private CalibratorHomographyImagePanel chomoip = new CalibratorHomographyImagePanel();
	private CalibratorHomographyImagePanel chomoipTest = new CalibratorHomographyImagePanel();
	private ImagePanelScroller ips = new ImagePanelScroller();
}
